docs: Recoup Content Agent guide and API reference#78
docs: Recoup Content Agent guide and API reference#78recoup-coding-agent merged 2 commits intomainfrom
Conversation
- Guide page covering @mention syntax, data flow, setup, and troubleshooting
- OpenAPI spec entries for POST /api/content-agent/{platform} and POST /api/content-agent/callback
- API reference pages for webhook and callback endpoints
- Navigation updated with Agents group in Guides tab and Content Agent group in API reference
Co-Authored-By: Paperclip <noreply@paperclip.ing>
📝 WalkthroughWalkthroughAdded comprehensive documentation and API specifications for a new Content Agent Slack bot feature, including endpoint definitions for webhook and callback operations, a detailed guide explaining the bot's control flow and setup process, and updated navigation structure. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
recoup-coding-agent
left a comment
There was a problem hiding this comment.
Code Review — Content Agent Documentation
Summary
This PR adds documentation for the Recoup Content Agent — a Slack bot that generates social-ready artist videos on @mention. Changes include a new guide page (content-agent.mdx), two API reference MDX pages (webhook + callback endpoints), two new OpenAPI path definitions, and navigation updates in docs.json.
CLEAN Code Assessment
- SRP: Clean separation — guide covers user-facing story, MDX pages cover API reference, openapi.json covers schema.
- DRY: No content duplication; guide cross-links to existing API reference pages rather than reproducing content.
- OCP: Additive only — new "Agents" navigation group in
docs.jsonwithout modifying any existing groups. - YAGNI: No speculative content;
platformenum constrained to["slack"]only.
Issues Found
suggestion — Webhook endpoint (POST /api/content-agent/{platform}) only defines 200 and 404 responses. The Slack integration performs signature verification (SLACK_CONTENT_SIGNING_SECRET), so a 401/403 response should be documented for signature verification failure.
suggestion — The callback path uses "security": [{"callbackSecret": []}] but callbackSecret is not declared in components/securitySchemes. Only apiKeyAuth is defined there. This will cause an OpenAPI validation warning. Fix:
"callbackSecret": {
"type": "apiKey",
"in": "header",
"name": "x-callback-secret",
"description": "Shared secret for callback authentication between the polling task and the API"
}nit — Webhook request body uses "type": "object" with no properties. Consider modeling the two known Slack event shapes (url_verification and app_mention) with oneOf discriminated by type.
nit — The Architecture table references internal source paths (lib/content-agent/bot.ts, lib/content-agent/handlers/). Fine for internal/developer-facing docs; noting in case this becomes public-facing.
Security
No concerns. Callback endpoint is correctly marked as not for external use with a separate callbackSecret scheme. No credentials present in the diff.
Verdict: Approve ✓
Well-structured PR that follows all repo conventions. The two suggestions (missing 401 response, undeclared security scheme) are worth a follow-up fix but are not blocking — the content is clear, accurate, and complete.
content-agent.mdx
Outdated
| 2. **Mention handler** parses the command, calls [`GET /api/content/validate`](/api-reference/content/validate) to check artist readiness | ||
| 3. **Content creation** triggered via [`POST /api/content/create`](/api-reference/content/create) — returns `runIds` | ||
| 4. **Poll task** (`poll-content-run`) monitors the Trigger.dev runs every 30 seconds (up to 30 minutes) | ||
| 5. **Callback** → `POST /api/content-agent/callback` receives results and posts video URLs back to the Slack thread |
There was a problem hiding this comment.
Why isn't this linked to the API docs?
| - Subscribe to `app_mention` bot event | ||
| 4. Install the app to your workspace | ||
|
|
||
| ### 2. Configure Environment Variables |
There was a problem hiding this comment.
Why is recoup Api key not listed here?
- Link POST /api/content-agent/callback to its API reference page in both the data flow section and endpoints table - Add missing RECOUP_API_KEY to environment variables table Co-Authored-By: Paperclip <noreply@paperclip.ing>
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@api-reference/openapi.json`:
- Around line 4637-4641: The OpenAPI document references a security requirement
named "callbackSecret" for POST /api/content-agent/callback but lacks a
corresponding entry in components.securitySchemes; add a new security scheme
named callbackSecret under components.securitySchemes (e.g., type: apiKey, in:
header, name: X-Callback-Secret or whichever header/query form your
implementation expects) so the reference resolves and the spec validates; update
the components object in api-reference/openapi.json to include this
callbackSecret scheme matching how the service verifies the secret.
- Around line 4504-4552: The POST operation for the
"/api/content-agent/{platform}" endpoint currently inherits the global
apiKeyAuth requirement; update the operation object for the POST (the entry
under "/api/content-agent/{platform}" -> "post") to explicitly override security
by adding "security": [] so the Slack webhook can be called without x-api-key
headers while leaving the rest of the operation intact (description, parameters,
requestBody, responses).
- Around line 4531-4546: The 200 response schema currently only documents { ok:
boolean } but must also allow the Slack url_verification challenge response;
update the "responses" -> "200" -> "content" -> "application/json" -> "schema"
to use a oneOf that includes two schemas: one object with a required "challenge"
(string) property (for url_verification) and one object with an "ok" (boolean)
property (for normal event ACKs). Ensure the oneOf entries clearly define the
"challenge" and "ok" properties and required fields so both response shapes
(challenge JSON and { "ok": true/false }) are valid.
In `@content-agent.mdx`:
- Around line 56-66: The Architecture docs currently list the webhook as "POST
/api/content-agent/slack" which conflicts with the OpenAPI path parameter;
update the table entry to use the parameterized path "POST
/api/content-agent/{platform}" (or alternately keep "POST
/api/content-agent/slack" and add a clarifying parenthetical "where
platform=slack") so the doc matches the OpenAPI spec; ensure this change is
applied to the Architecture table row for "Slack webhook" so readers see the
same path format as the OpenAPI definition.
- Around line 26-54: The `@RecoupContentAgent` mention docs list only
artist_account_id, template, batch and lipsync but omit ContentCreateRequest
fields caption_length and upscale; update the documentation for the
`@RecoupContentAgent` syntax to either (a) add parameters for caption_length
(short/medium/long) and upscale (boolean) with descriptions and example usages
(e.g., include "caption_length=short" and "upscale" tokens) or (b) add a
single-line note under the syntax indicating the bot exposes a simplified
interface and that additional ContentCreateRequest options (caption_length,
upscale) are not supported via mention and must be set via the full API;
reference the `@RecoupContentAgent` mention and the ContentCreateRequest schema
when making the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7a10bd99-9ced-45eb-a396-d3b8c31e3181
📒 Files selected for processing (5)
api-reference/content-agent/callback.mdxapi-reference/content-agent/webhook.mdxapi-reference/openapi.jsoncontent-agent.mdxdocs.json
| "/api/content-agent/{platform}": { | ||
| "post": { | ||
| "description": "Webhook endpoint for the Recoup Content Agent Slack bot. Receives @mention events from Slack and triggers content generation for the mentioned artist. The bot parses the mention text for `<artist_account_id> [template] [batch=N] [lipsync]`, validates the artist, calls POST /api/content/create, and starts a background polling task that reports results back to the Slack thread.\n\nFor Slack, also handles `url_verification` challenges during app setup.", | ||
| "parameters": [ | ||
| { | ||
| "name": "platform", | ||
| "in": "path", | ||
| "description": "Chat platform identifier. Currently supports `slack`.", | ||
| "required": true, | ||
| "schema": { | ||
| "type": "string", | ||
| "enum": ["slack"] | ||
| } | ||
| } | ||
| ], | ||
| "requestBody": { | ||
| "description": "Slack Events API payload (app_mention event or url_verification challenge)", | ||
| "required": true, | ||
| "content": { | ||
| "application/json": { | ||
| "schema": { | ||
| "type": "object", | ||
| "description": "Slack Events API envelope — the shape depends on the event type" | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| "responses": { | ||
| "200": { | ||
| "description": "Event processed successfully", | ||
| "content": { | ||
| "application/json": { | ||
| "schema": { | ||
| "type": "object", | ||
| "properties": { | ||
| "ok": { | ||
| "type": "boolean" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| "404": { | ||
| "description": "Unknown platform" | ||
| } | ||
| } | ||
| } | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's check the structure of the openapi.json file and find the global security definition
head -100 api-reference/openapi.json | grep -A 10 '"security"' || echo "Checking file structure..."Repository: recoupable/docs
Length of output: 441
🏁 Script executed:
# Get the full context around lines 4504-4552 to see the endpoint and any security override
sed -n '4490,4560p' api-reference/openapi.jsonRepository: recoupable/docs
Length of output: 2833
🏁 Script executed:
# Search for the top-level security definition to confirm global apiKeyAuth
rg '"security"\s*:' api-reference/openapi.json -B 5 -A 10 | head -80Repository: recoupable/docs
Length of output: 2850
🏁 Script executed:
# Check if there are other webhook or public endpoints with "security": [] override
rg '"security"\s*:\s*\[\]' api-reference/openapi.json -B 15 -A 5Repository: recoupable/docs
Length of output: 41
Webhook endpoint incorrectly inherits global apiKeyAuth requirement.
The /api/content-agent/{platform} endpoint lacks an explicit security override and therefore requires x-api-key authentication. Slack webhooks are initiated by Slack's servers and cannot include custom API key headers—they rely on signature verification instead. This endpoint must override the global security with "security": [] to function as a webhook.
Required fix
"/api/content-agent/{platform}": {
"post": {
+ "security": [],
"description": "Webhook endpoint for the Recoup Content Agent Slack bot. Receives `@mention` events from Slack and triggers content generation for the mentioned artist. The bot parses the mention text for `<artist_account_id> [template] [batch=N] [lipsync]`, validates the artist, calls POST /api/content/create, and starts a background polling task that reports results back to the Slack thread.\n\nFor Slack, also handles `url_verification` challenges during app setup.",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@api-reference/openapi.json` around lines 4504 - 4552, The POST operation for
the "/api/content-agent/{platform}" endpoint currently inherits the global
apiKeyAuth requirement; update the operation object for the POST (the entry
under "/api/content-agent/{platform}" -> "post") to explicitly override security
by adding "security": [] so the Slack webhook can be called without x-api-key
headers while leaving the rest of the operation intact (description, parameters,
requestBody, responses).
| "responses": { | ||
| "200": { | ||
| "description": "Event processed successfully", | ||
| "content": { | ||
| "application/json": { | ||
| "schema": { | ||
| "type": "object", | ||
| "properties": { | ||
| "ok": { | ||
| "type": "boolean" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Slack Events API url_verification response format (what exact JSON/body is required for challenge acknowledgement?)
💡 Result:
The Slack Events API sends a url_verification challenge during Request URL configuration. Respond with HTTP 200 OK and the exact challenge value from the incoming JSON payload. Supported response formats (any one works): 1. Plaintext (recommended): Content-Type: text/plain Body: 3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P 2. Form-urlencoded: Content-Type: application/x-www-form-urlencoded Body: challenge=3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P 3. JSON: Content-Type: application/json Body: {"challenge":"3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P"} Incoming payload example: { "token": "Jhj5dZrVaK7ZwHHjRyZWjbDl", "challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P", "type": "url_verification" } Respond immediately with the challenge value (no JSON wrapper required). Verify request authenticity using signing secrets for production events.
Citations:
- 1: https://docs.slack.dev/reference/events/url_verification
- 2: https://api.slack.com/events/url_verification
- 3: https://docs.slack.dev/apis/events-api/using-http-request-urls
🏁 Script executed:
# First, let's see the broader context of the endpoint around lines 4531-4546
sed -n '4500,4580p' api-reference/openapi.json | cat -nRepository: recoupable/docs
Length of output: 3964
🏁 Script executed:
# Also search for the endpoint name/path to understand what this endpoint is
grep -n "url_verification\|/events\|challenge" api-reference/openapi.json | head -30Repository: recoupable/docs
Length of output: 651
Response schema must document the url_verification challenge response.
The endpoint explicitly handles Slack url_verification challenges during app setup (per the description), but the 200 response schema only documents { ok: boolean }. According to Slack's Events API, url_verification requests require responding with the challenge value in JSON format: {"challenge": "<value>"}.
Update the response schema to use oneOf to cover both response cases: the challenge response for url_verification events and the ok response for regular events.
Proposed fix
"200": {
"description": "Event processed successfully",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "ok": {
- "type": "boolean"
- }
- }
+ "oneOf": [
+ {
+ "type": "object",
+ "required": ["challenge"],
+ "properties": {
+ "challenge": { "type": "string" }
+ }
+ },
+ {
+ "type": "object",
+ "properties": {
+ "ok": { "type": "boolean" }
+ }
+ }
+ ]
}
}
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "responses": { | |
| "200": { | |
| "description": "Event processed successfully", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "type": "object", | |
| "properties": { | |
| "ok": { | |
| "type": "boolean" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "responses": { | |
| "200": { | |
| "description": "Event processed successfully", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "oneOf": [ | |
| { | |
| "type": "object", | |
| "required": ["challenge"], | |
| "properties": { | |
| "challenge": { "type": "string" } | |
| } | |
| }, | |
| { | |
| "type": "object", | |
| "properties": { | |
| "ok": { "type": "boolean" } | |
| } | |
| } | |
| ] | |
| } | |
| } | |
| } | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@api-reference/openapi.json` around lines 4531 - 4546, The 200 response schema
currently only documents { ok: boolean } but must also allow the Slack
url_verification challenge response; update the "responses" -> "200" ->
"content" -> "application/json" -> "schema" to use a oneOf that includes two
schemas: one object with a required "challenge" (string) property (for
url_verification) and one object with an "ok" (boolean) property (for normal
event ACKs). Ensure the oneOf entries clearly define the "challenge" and "ok"
properties and required fields so both response shapes (challenge JSON and {
"ok": true/false }) are valid.
| "security": [ | ||
| { | ||
| "callbackSecret": [] | ||
| } | ||
| ] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python - <<'PY'
import json, sys
with open("api-reference/openapi.json", "r", encoding="utf-8") as f:
doc = json.load(f)
schemes = set(doc.get("components", {}).get("securitySchemes", {}).keys())
missing = []
for path, item in doc.get("paths", {}).items():
for method, op in item.items():
if method.lower() not in {"get","post","put","patch","delete","head","options","trace"}:
continue
for req in op.get("security", []):
for name in req.keys():
if name not in schemes:
missing.append((path, method.upper(), name))
if missing:
print("Missing security scheme definitions:")
for m in missing:
print(f"- {m[1]} {m[0]} -> {m[2]}")
sys.exit(1)
print("All referenced security schemes are defined.")
PYRepository: recoupable/docs
Length of output: 148
Add missing callbackSecret security scheme definition to OpenAPI spec.
The callbackSecret security scheme is referenced at POST /api/content-agent/callback but not defined in securitySchemes, making the OpenAPI document invalid for tooling that resolves security references.
🔧 Proposed fix
@@
"securitySchemes": {
+ "callbackSecret": {
+ "type": "apiKey",
+ "in": "header",
+ "name": "x-callback-secret",
+ "description": "Shared secret for internal content-agent callback authentication."
+ },
"bearerAuth": {
"type": "http",
"scheme": "bearer"
},🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@api-reference/openapi.json` around lines 4637 - 4641, The OpenAPI document
references a security requirement named "callbackSecret" for POST
/api/content-agent/callback but lacks a corresponding entry in
components.securitySchemes; add a new security scheme named callbackSecret under
components.securitySchemes (e.g., type: apiKey, in: header, name:
X-Callback-Secret or whichever header/query form your implementation expects) so
the reference resolves and the spec validates; update the components object in
api-reference/openapi.json to include this callbackSecret scheme matching how
the service verifies the secret.
| ### @Mention Syntax | ||
|
|
||
| ``` | ||
| @RecoupContentAgent <artist_account_id> [template] [batch=N] [lipsync] | ||
| ``` | ||
|
|
||
| | Parameter | Required | Description | | ||
| |-----------|----------|-------------| | ||
| | `artist_account_id` | Yes | UUID of the artist account | | ||
| | `template` | No | Content template name (defaults to `artist-caption-bedroom`) | | ||
| | `batch=N` | No | Number of videos to generate (1-30, default 1) | | ||
| | `lipsync` | No | Enable lipsync mode (audio baked into video) | | ||
|
|
||
| ### Examples | ||
|
|
||
| **Basic — single video with default template:** | ||
| ``` | ||
| @RecoupContentAgent abc-123-uuid | ||
| ``` | ||
|
|
||
| **Custom template:** | ||
| ``` | ||
| @RecoupContentAgent abc-123-uuid artist-caption-bedroom | ||
| ``` | ||
|
|
||
| **Batch with lipsync:** | ||
| ``` | ||
| @RecoupContentAgent abc-123-uuid batch=3 lipsync | ||
| ``` |
There was a problem hiding this comment.
Consider documenting all ContentCreateRequest parameters.
The @mention syntax currently documents artist_account_id, template, batch, and lipsync, but the ContentCreateRequest schema also includes caption_length (short/medium/long) and upscale (boolean) parameters.
If these parameters are intentionally omitted from the bot interface, consider adding a note explaining that the bot provides a simplified interface. Otherwise, document how users can pass these additional options.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@content-agent.mdx` around lines 26 - 54, The `@RecoupContentAgent` mention docs
list only artist_account_id, template, batch and lipsync but omit
ContentCreateRequest fields caption_length and upscale; update the documentation
for the `@RecoupContentAgent` syntax to either (a) add parameters for
caption_length (short/medium/long) and upscale (boolean) with descriptions and
example usages (e.g., include "caption_length=short" and "upscale" tokens) or
(b) add a single-line note under the syntax indicating the bot exposes a
simplified interface and that additional ContentCreateRequest options
(caption_length, upscale) are not supported via mention and must be set via the
full API; reference the `@RecoupContentAgent` mention and the ContentCreateRequest
schema when making the change.
| ## Architecture | ||
|
|
||
| The content agent follows the same pattern as the coding agent bot: | ||
|
|
||
| | Component | Location | Purpose | | ||
| |-----------|----------|---------| | ||
| | Slack webhook | `POST /api/content-agent/slack` | Receives @mention events | | ||
| | Callback endpoint | `POST /api/content-agent/callback` | Receives polling results | | ||
| | Bot singleton | `lib/content-agent/bot.ts` | Chat SDK with Slack adapter + Redis state | | ||
| | Mention handler | `lib/content-agent/handlers/` | Parses args, validates artist, triggers pipeline | | ||
| | Poll task | `poll-content-run` (Trigger.dev) | Monitors content runs, posts results via callback | |
There was a problem hiding this comment.
Align webhook endpoint with OpenAPI path parameter.
The Architecture table shows POST /api/content-agent/slack, but the OpenAPI spec defines this as POST /api/content-agent/{platform} with platform as a path parameter. Consider using either:
- The parameterized form:
POST /api/content-agent/{platform} - A note clarifying:
POST /api/content-agent/slack(whereplatform=slack)
This ensures consistency between the guide and the API reference.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@content-agent.mdx` around lines 56 - 66, The Architecture docs currently list
the webhook as "POST /api/content-agent/slack" which conflicts with the OpenAPI
path parameter; update the table entry to use the parameterized path "POST
/api/content-agent/{platform}" (or alternately keep "POST
/api/content-agent/slack" and add a clarifying parenthetical "where
platform=slack") so the doc matches the OpenAPI spec; ensure this change is
applied to the Architecture table row for "Slack webhook" so readers see the
same path format as the OpenAPI definition.
Summary
content-agent.mdx): How the Slack bot works, @mention syntax, architecture, setup instructions, and troubleshootingPOST /api/content-agent/{platform}(webhook) andPOST /api/content-agent/callback(internal callback)Follows documentation-driven development — these docs describe the content-agent scaffold from recoupable/api#341 and recoupable/tasks#109.
Test plan
npx mintlify@latest devand verify the guide renders correctlySummary by CodeRabbit